/*
 *  ShaderMain.cpp
 *  RTR
 *
 *  Created by Bernardo Franceschin on 4/21/11.
 *  Copyright 2011 PUC-Rio. All rights reserved.
 *
 */

#include<stdio.h>
#include<stdlib.h>
#include"glew.h"
#include"glheader.h"
#include"vshader.h"
#include"vmatrix.h"
#include"vmesh.h"
#include"vsphere.h"
#include"vtorus.h"
#include"vcylinder.h"
#include "manipulator.h"

static VShader * shader;
static VMatrix * vmatrix;
static VMesh * bunny;
static VSphere * sphere;
static bool ellipse = true;
static VTorus  * torus;
static VGrid * flat;
static VShape * shape;
static VCylinder * cylinder;
static VManipulator* manip;
static bool wireframeEnabled;

void Keyboard(unsigned char key, int x, int y)
{
	switch ( key )
	{
    case 'b':
      shape = bunny;
      ellipse=false;
      break;
    case 's':
      shape = sphere;
      ellipse=false;
      break;
    case 'e':
      shape = sphere;
      ellipse=true;
      break;
    case 't':
      shape = torus;
      ellipse=false;
      break;
    case 'f':
      shape = flat;
      ellipse=false;
      break;
    case 'c':
      shape = cylinder;
      ellipse=false;
      break;
    case 'w':
      wireframeEnabled = !wireframeEnabled;
      if(wireframeEnabled)
        glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
      else   glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
      break;      
		case 27:
		case 'q':
		case 'Q':
			exit(0);
	}
  glutPostRedisplay();
}

void Redraw ()
{
  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  int vp[4];
  glGetIntegerv(GL_VIEWPORT,vp);
  float xmin, xmax, ymin, ymax, zmin, zmax;
  shape->GetBBox(&xmin, &xmax, &ymin, &ymax, &zmin, &zmax);
  shape->SetVertId(VPOS);
  shape->SetNormalId(VNORMAL);
  float xcenter = (xmin+xmax) / 2;
  float ycenter = (ymin+ymax) / 2;
  float zcenter = (zmin+zmax) / 2;
  float zdist = 2*(zmax-zmin);
  vmatrix->SetMode(VM_PROJECTION);
  vmatrix->LoadIdentity();
  vmatrix->Perspective(50.0f, (float)vp[2]/vp[3], 0.1f, 100.0f);
  vmatrix->SetMode(GL_MODELVIEW);
  vmatrix->LoadIdentity();
  manip->SetZCenter(zdist);
  manip->Load();
  vmatrix->LookAt(xcenter, ycenter, zcenter-zdist,
            xcenter, ycenter, zcenter,
            0.0f, 1.0f, 0.0f
           );
  shader->SetAsCurrent();
  //int  l_id = glGetUniformLocation(shader->GetPid(), "lightPos");
  //if(l_id == -1){
    //printf("lightPos not found.\n");
  //}
  //float lpos[4] = {0.0f, 10.0f, 0.0f, 1.0f};
  //float lpos[4] = {0.0f, 0.0f, 0.0f, 1.0f};
  //glUniform4fv(l_id, 1, lpos);
  if(ellipse)
    vmatrix->Scale(1.0,1.5,1.0);
  vmatrix->SetUniformVar(shader->GetPid());
  shape->Draw();
  glutSwapBuffers();
}

static void Init (char * vs, char* fs)
{
  GLenum err = glewInit();
  if (GLEW_OK != err) { 
    fprintf(stderr, "GLEW Error: %s\n", glewGetErrorString(err));
    exit(-1);
  }
  glClearColor(1.0f, 1.0f, 1.0f, 1.0f); 
  //glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
  glEnable(GL_DEPTH_TEST);
  shader = new VShader();
  shader->SetVertFile(vs);
  shader->SetFragFile(fs);
  shader->CreateProgram();
  vmatrix = new VMatrix();
  bunny = new VMesh(DRAG);
  manip = VManipulator::Instance();
  manip->SetMatrixStack(vmatrix);
  torus = new VTorus(100);
  sphere = new VSphere(100);
  cylinder = new VCylinder(100,0.02);
  //cylinder->SinShape();
  cylinder->KnotShape();
  flat = new VGrid(100);
  flat->FillCoordAndBox();
  flat->CalcNormals();
  shape = sphere;
}

int main (int argc, char** argv)
{
  if(argc<3){
    printf("Numero insuficiente de argumentos\n");
    return 0;
  }
  int gac=0;
  glutInit(&gac, NULL);
  glutInitDisplayMode(GLUT_DOUBLE | GLUT_DEPTH | GLUT_RGBA);
  glutInitWindowSize(800,800);
  glutCreateWindow("ShaderTest");
  glutDisplayFunc(Redraw);
  glutKeyboardFunc(Keyboard);
  Init(argv[1],argv[2]);
  glutMainLoop();
  return 0;
}
